package service

import (
	"context"
	"database/sql"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"mall/api/bilinadmin"
	"mall/api/mall"
	"mall/api/prod"
	"mall/internal/constant"
	"mall/internal/model"
	"mall/pkg/ecode"
	"mall/pkg/util"
	"strings"
	"time"
)

// 导入供货组/商品库商品下拉框
func (s *Service) QueryProdsExcludeShelf(ctx context.Context, req *mall.QueryProdsExcludeShelfRequest) (
	resp *mall.QueryProdsExcludeShelfResp, err error) {
	if req.FromMenu && req.PStoreId == 0 {
		err = ecode.BadRequest("总部货架不能从供货组导入商品")
		return
	}
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		shelfProdIds []uint64
		prodResp     *prod.GetProdListResponse
	)
	if shelfProdIds, err = s.dao.FindAllShelfProdIds(ctx, req.Token.SgId, req.PStoreId); err != nil {
		return
	}
	if req.FromMenu {
		// 从供货组获取
		if prodResp, err = s.downstream.SelectionMenuProdList(ctx, req, shelfProdIds); err != nil {
			return
		}
	} else {
		// 从商品库获取
		if prodResp, err = s.downstream.SelectionProdList(ctx, req, shelfProdIds); err != nil {
			return
		}
	}
	resp = &mall.QueryProdsExcludeShelfResp{
		Total: prodResp.Total,
		Prods: prodResp.Prods,
	}
	return
}

// 查看货架商品
func (s *Service) GetShelfProds(ctx context.Context, req *mall.ShelfProdsQueryRequest) (
	resp *mall.ShelfProdsQueryResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	resp = &mall.ShelfProdsQueryResp{}
	var (
		shelfProds []*model.ShelfProd
		skus       []*model.ShelfSku
		groups     []*model.GroupRefQueryModel
	)
	if resp.Total, shelfProds, err = s.dao.FindShelfProdByCondition(
		ctx, req.Token.SgId, req.PStoreId, req.PageNo, req.PageSize,
		req.ProdTypeId, req.GroupId, req.ExcludedGroupId, req.GroupStatus, req.Status, req.Query); err != nil {
		return
	}
	resp.Prods = make([]*mall.ShelfProd, len(shelfProds))
	if len(shelfProds) != 0 {
		prodIds := make([]uint64, len(shelfProds))
		for i, p := range shelfProds {
			prodIds[i] = p.ProdId
		}
		if skus, err = s.dao.FindShelfSkusByProdIds(ctx, req.Token.SgId, req.PStoreId, prodIds); err != nil {
			return
		}
		if groups, err = s.dao.FindGroupViewsByProdIds(ctx, req.PStoreId, prodIds); err != nil {
			return
		}
		skuMap := make(map[uint64][]*prod.SimpleSkuView)
		groupMap := make(map[uint64][]string)
		priceRangeDict := getPriceRangeDict(skus)
		for _, sku := range skus {
			if _, ok := skuMap[sku.ProdId]; !ok {
				skuMap[sku.ProdId] = make([]*prod.SimpleSkuView, 0)
			}
			price := getCustomPrice(sku)
			skuMap[sku.ProdId] = append(skuMap[sku.ProdId], &prod.SimpleSkuView{
				Id:    sku.SkuId,
				Name:  strings.Join(sku.SyncItems, "/"),
				Price: uint32(price),
			})
		}
		for _, group := range groups {
			if _, ok := groupMap[group.ProdID]; !ok {
				groupMap[group.ProdID] = make([]string, 0)
			}
			groupMap[group.ProdID] = append(groupMap[group.ProdID], group.GroupName)
		}
		for i, p := range shelfProds {
			groupNames, ok := groupMap[p.ProdId]
			if !ok {
				groupNames = make([]string, 0)
			}
			resp.Prods[i] = &mall.ShelfProd{
				Id:             p.ProdId,
				Name:           p.SyncName,
				CustomName:     p.CustomName,
				PriceRange:     priceRangeDict[p.ProdId],
				ProdGroupNames: groupNames,
				Status:         p.ShelfStatus,
				TitlePic:       p.SyncPic,
				Skus:           skuMap[p.ProdId],
				FromMenu:       p.FromMenu,
			}
		}
	}
	return
}

// 批量导入/创建商品到货架
func (s *Service) CreateShelfProds(ctx context.Context, req *mall.BatchShelfProdsWithStatusRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		inputProds   []*prod.SelectionProdView
		existProdIds []uint64
	)
	if req.FromMenu {
		if req.PStoreId == 0 {
			err = ecode.BadRequest("总部货架不能从供货组导入商品")
			return
		}
		if inputProds, err = s.downstream.SelectionMenuProdsByProdIds(
			ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
			return
		}
	} else {
		var prodResp *prod.SelectionProdsFullResponse
		if prodResp, err = s.downstream.SelectionProdsByProdIds(
			ctx, req.Token.SgId, req.Ids, false); err != nil {
			return
		}
		inputProds = prodResp.Prods
	}
	if len(inputProds) != len(req.Ids) {
		err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选商品包括已删除商品，请刷新列表重试")
		return
	}
	if existProdIds, err = s.dao.FindShelfProdIdsByProdIds(ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
		return
	}
	existProdMap := make(util.Int64BoolMap)
	for _, prodId := range existProdIds {
		existProdMap[prodId] = true
	}
	inputMap := make(map[uint64]*prod.SelectionProdView)
	for _, inputProd := range inputProds {
		if _, ok := existProdMap[inputProd.Id]; ok {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品%s已在货架上，无需重复添加", inputProd.Name)
			return
		}
		inputMap[inputProd.Id] = inputProd
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		now := time.Now()
		for _, prodId := range req.Ids {
			inputProd := inputMap[prodId]
			if err = s.dao.Create(ctx, &model.ShelfProd{
				ProdId:           prodId,
				PStoreId:         req.PStoreId,
				SgId:             req.Token.SgId,
				FromMenu:         req.FromMenu,
				CustomName:       "",
				SyncName:         inputProd.Name,
				SyncTypeId:       inputProd.ProdTypeId,
				SyncNature:       uint8(inputProd.Nature),
				SyncPic:          inputProd.Pic,
				SyncUnit:         inputProd.Unit,
				SyncGroups:       inputProd.GroupList,
				SyncGroupDetails: inputProd.GroupDetail,
				SyncTime:         now,
				ShelfStatus:      req.Status,
				Operator:         req.Token.EmpId,
			}); err != nil {
				return
			}
			for _, sku := range inputProd.Skus {
				if err = s.dao.Create(ctx, &model.ShelfSku{
					SkuId:        sku.Id,
					PStoreId:     req.PStoreId,
					ProdId:       prodId,
					SgId:         req.Token.SgId,
					CustomPrice:  0,
					IsCustomized: false,
					SyncItems:    sku.Items,
					SyncPrice:    uint64(sku.Price),
					SyncWeight:   sku.Weight,
					SyncTime:     now,
					Operator:     req.Token.EmpId,
				}); err != nil {
					return
				}
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 删除商品(支持批量)
func (s *Service) DeleteShelfProds(ctx context.Context, req *mall.ShelfProdsDeleteRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var existProdIds []uint64
		if existProdIds, err = s.dao.FindShelfProdIdsByProdIds(ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
			return
		}
		if len(existProdIds) != len(req.Ids) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在货架上，无法操作")
			return
		}
		if err = s.dao.DeleteShelfProds(ctx, req.PStoreId, req.Ids); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 批量上下架
func (s *Service) BatchShelfProdsUpdateStatus(ctx context.Context, req *mall.BatchShelfProdsWithStatusRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var existProdIds []uint64
		if existProdIds, err = s.dao.FindShelfProdIdsByProdIds(ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
			return
		}
		if len(existProdIds) != len(req.Ids) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在货架上，无法操作")
			return
		}
		if err = s.dao.BatchUpdateShelfStatus(
			ctx, req.PStoreId, req.Ids, req.Status, req.Token.EmpId); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

func (s *Service) canModifyPrice(ctx context.Context, token *mall.WebToken, pStoreId uint32) (err error) {
	if pStoreId != 0 {
		var (
			config         *model.Config
			canModifyPrice bool
		)
		if config, err = s.dao.GetConfig(ctx, token.SgId); err != nil {
			return
		}
		if bilinadmin.BizTypeEnum(config.OperationMode) == bilinadmin.BizTypeEnum_agent {
			// 经销商模式需要检查供货组是否允许改价
			if canModifyPrice, err = s.downstream.CheckCanModifyPrice(ctx, token, pStoreId); err != nil {
				return
			} else if !canModifyPrice {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "当前门店所在供货组不允许改价")
				return
			}
		}
	}
	return
}

// 批量修改商品价格
func (s *Service) BatchShelfProdsUpdatePrice(ctx context.Context, req *mall.ShelfProdsBatchPriceRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			inputSkusIds            []uint64
			existedProds            []*model.ShelfProd
			skus                    []*model.ShelfSku
			isCanModifyPriceChecked bool
		)
		inputProdIdMap := make(util.Int64BoolMap)
		skuPriceMap := make(map[uint64]uint64)
		for _, p := range req.Prods {
			inputProdIdMap[p.Id] = true
			for _, sku := range p.Skus {
				inputSkusIds = append(inputSkusIds, sku.Id)
				skuPriceMap[sku.Id] = sku.CustomPrice
			}
		}
		if existedProds, err = s.dao.FindShelfProdsByProdIds(
			ctx, req.Token.SgId, req.PStoreId, inputProdIdMap.GetKeys()); err != nil {
			return
		}
		if skus, err = s.dao.FindShelfSkusBySkuIds(ctx, req.PStoreId, inputSkusIds); err != nil {
			return
		}
		if len(existedProds) != len(inputProdIdMap) || len(inputSkusIds) != len(skus) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在货架上，无法操作")
			return
		}
		menuProdMap := make(util.Int64BoolMap)
		for _, existedProd := range existedProds {
			if existedProd.FromMenu {
				menuProdMap[existedProd.ProdId] = true
			}
		}
		for _, sku := range skus {
			if sku.SyncPrice != skuPriceMap[sku.SkuId] {
				if _, ok := menuProdMap[sku.ProdId]; ok && !isCanModifyPriceChecked {
					if err = s.canModifyPrice(ctx, req.Token, req.PStoreId); err != nil {
						return
					}
				}
				sku.IsCustomized = true
				sku.CustomPrice = skuPriceMap[sku.SkuId]
			} else {
				sku.IsCustomized = false
				sku.CustomPrice = sku.SyncPrice
			}
			sku.Operator = req.Token.EmpId
			if err = s.dao.AutoUpdate(ctx, sku); err != nil {
				return
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 批量对多个商品追加多个分组
func (s *Service) BatchShelfProdsAddToGroup(ctx context.Context, req *mall.ShelfProdsBatchAddGroupsRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			existProdIds                    []uint64
			groups                          []*model.ShelfGroup
			existGroupRefs, insertGroupRefs []*model.ShelfGroupRef
		)
		if existProdIds, err = s.dao.FindShelfProdIdsByProdIds(ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
			return
		}
		if len(existProdIds) != len(req.Ids) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在货架上，无法操作")
			return
		}
		if groups, err = s.dao.FindShelfGroupsByGroupIds(
			ctx, req.GroupIds, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
		if len(groups) != len(req.GroupIds) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选分组部分已删除，无法操作")
			return
		}
		if existGroupRefs, err = s.dao.FindShelfGroupRefByProdIdsAndGroupIds(ctx, req.Ids, req.GroupIds); err != nil {
			return
		}
		existMap := make(map[uint32]util.Int64BoolMap)
		for _, ref := range existGroupRefs {
			if _, ok := existMap[ref.GroupId]; !ok {
				existMap[ref.GroupId] = make(util.Int64BoolMap)
			}
			existMap[ref.GroupId][ref.ProdId] = true
		}
		for _, prodId := range req.Ids {
			for _, groupId := range req.GroupIds {
				if existProdMap, hasGroup := existMap[groupId]; hasGroup {
					if _, hasProd := existProdMap[prodId]; hasProd {
						// 存在则跳过
						continue
					}
				}
				insertGroupRefs = append(insertGroupRefs, &model.ShelfGroupRef{
					GroupId:  groupId,
					ProdId:   prodId,
					Operator: req.Token.EmpId,
					SgId:     req.Token.SgId,
					PStoreId: req.PStoreId,
				})
			}
		}
		if err = s.dao.BatchCreate(ctx, insertGroupRefs, len(insertGroupRefs)); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 货架分组批量移除多个货架商品
func (s *Service) RemoveProdsInShelfGroup(ctx context.Context, req *mall.ShelfProdsBatchRemovesGroupRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			existProdIds   []uint64
			existGroupRefs []*model.ShelfGroupRef
		)
		if existProdIds, err = s.dao.FindShelfProdIdsByProdIds(ctx, req.Token.SgId, req.PStoreId, req.Ids); err != nil {
			return
		}
		if len(existProdIds) != len(req.Ids) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在货架上，无法操作")
			return
		}
		if _, err = s.dao.GetShelfGroup(ctx, req.GroupId, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		if existGroupRefs, err = s.dao.FindShelfGroupRefByProdIdsAndGroupIds(
			ctx, req.Ids, []uint32{req.GroupId}); err != nil {
			return
		}
		if len(existGroupRefs) != len(existProdIds) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh,
				"所选商品部分已不在分组中，无法操作")
		}
		if err = s.dao.DeleteShelfGroupRefByProdIds(ctx, req.GroupId, req.Ids); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 查看商品详情
func (s *Service) GetSingleProdDetail(ctx context.Context, req *mall.CommonObject64Request) (
	resp *mall.GetSingleProdDetailResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var (
		shelfProd     *model.ShelfProd
		prodView      *prod.ProdView
		queryPStoreId uint32
		skus          []*model.ShelfSku
		groups        []*model.GroupRefQueryModel
	)
	if shelfProd, err = s.dao.GetShelfProd(ctx, req.Id, req.Token.SgId, req.PStoreId); err != nil {
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			err = constant.ErrObjectNotExist
			return
		}
		return
	}
	if shelfProd.FromMenu {
		queryPStoreId = 0
	} else {
		queryPStoreId = shelfProd.PStoreId
	}
	if prodView, err = s.downstream.GetProdInfo(ctx, req.Token.SgId, queryPStoreId, req.Id, false); err != nil {
		return
	}
	if skus, err = s.dao.FindShelfSkusByProdIds(ctx, req.Token.SgId, req.PStoreId, []uint64{req.Id}); err != nil {
		return
	}
	if groups, err = s.dao.FindGroupViewsByProdIds(ctx, req.PStoreId, []uint64{req.Id}); err != nil {
		return
	}
	resp = &mall.GetSingleProdDetailResp{
		Id:         req.Id,
		CustomName: shelfProd.CustomName,
		Groups:     make([]*mall.GroupSimpleView, len(groups)),
		Status:     shelfProd.ShelfStatus,
		Skus:       make([]*mall.CustomSkuPrice, 0),
		ProdInfo:   prodView,
	}
	for i, group := range groups {
		resp.Groups[i] = &mall.GroupSimpleView{
			Id:   group.GroupId,
			Name: group.GroupName,
		}
	}
	for _, sku := range skus {
		if sku.IsCustomized {
			resp.Skus = append(resp.Skus, &mall.CustomSkuPrice{
				Id:          sku.SkuId,
				CustomPrice: sku.CustomPrice,
			})
		}
	}
	return
}

// 修改商品详情
func (s *Service) UpdateSingleProd(ctx context.Context, req *mall.UpdateSingleProdRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			shelfProd               *model.ShelfProd
			groups                  []*model.ShelfGroup
			existGroupRefs          []*model.ShelfGroupRef
			skus                    []*model.ShelfSku
			isCanModifyPriceChecked bool
		)
		if shelfProd, err = s.dao.GetShelfProd(ctx, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		if len(req.GroupIds) != 0 {
			if groups, err = s.dao.FindShelfGroupsByGroupIds(
				ctx, req.GroupIds, req.Token.SgId, req.PStoreId); err != nil {
				return
			}
			if len(groups) != len(req.GroupIds) {
				err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选分组不可用，请刷新列表重试")
				return
			}
		}
		if skus, err = s.dao.FindShelfSkusByProdIds(ctx, req.Token.SgId, req.PStoreId, []uint64{req.Id}); err != nil {
			return
		}
		if len(req.Skus) != len(skus) {
			err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选商品规格不可用，请刷新列表重试")
			return
		}
		if existGroupRefs, err = s.dao.FindShelfGroupRefByProdIds(
			ctx, req.Token.SgId, req.PStoreId, []uint64{req.Id}); err != nil {
			return
		}
		inputGroupIdMap := make(util.Int32BoolMap)
		existGroupIdMap := make(util.Int32BoolMap)
		for _, groupId := range req.GroupIds {
			inputGroupIdMap[groupId] = true
		}
		for _, ref := range existGroupRefs {
			existGroupIdMap[ref.GroupId] = true
		}
		skuPriceMap := make(map[uint64]uint64)
		for _, sku := range req.Skus {
			skuPriceMap[sku.Id] = sku.CustomPrice
		}
		shelfProd.CustomName = req.CustomName
		shelfProd.Operator = req.Token.EmpId
		for _, sku := range skus {
			if sku.SyncPrice != skuPriceMap[sku.SkuId] {
				if shelfProd.FromMenu && !isCanModifyPriceChecked {
					if err = s.canModifyPrice(ctx, req.Token, req.PStoreId); err != nil {
						return
					}
				}
				sku.IsCustomized = true
				sku.CustomPrice = skuPriceMap[sku.SkuId]
				sku.Operator = req.Token.EmpId
				if err = s.dao.AutoUpdate(ctx, sku); err != nil {
					return
				}
			} else {
				sku.IsCustomized = false
				sku.CustomPrice = sku.SyncPrice
				sku.Operator = req.Token.EmpId
				if err = s.dao.AutoUpdate(ctx, sku); err != nil {
					return
				}
			}
		}
		if err = s.dao.AutoUpdate(ctx, shelfProd); err != nil {
			return
		}
		for _, groupId := range req.GroupIds {
			if _, ok := existGroupIdMap[groupId]; ok {
				delete(inputGroupIdMap, groupId)
				delete(existGroupIdMap, groupId)
			}
		}
		for groupId := range inputGroupIdMap {
			if err = s.dao.Create(ctx, &model.ShelfGroupRef{
				GroupId:  groupId,
				ProdId:   req.Id,
				Operator: req.Token.EmpId,
				SgId:     req.Token.SgId,
				PStoreId: req.PStoreId,
			}); err != nil {
				return
			}
		}
		if len(existGroupIdMap) != 0 {
			if err = s.dao.DeleteShelfGroupRefByGroupIds(ctx, existGroupIdMap.GetKeys(), req.Id); err != nil {
				return
			}
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 查看货架分组列表
func (s *Service) GetShelfGroups(ctx context.Context, req *mall.CommonRequest) (
	resp *mall.GetShelfGroupsResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var groups []*model.ShelfGroup
	if groups, err = s.dao.FindShelfGroupsBySgId(ctx, req.Token.SgId, req.PStoreId); err != nil {
		return
	}
	resp = &mall.GetShelfGroupsResp{
		Groups: make([]*mall.GroupSimpleView, len(groups)),
	}
	for i, group := range groups {
		resp.Groups[i] = &mall.GroupSimpleView{
			Id:   group.ID,
			Name: group.Name,
		}
	}
	return
}

// 新建货架分组
func (s *Service) CreateShelfGroup(ctx context.Context, req *mall.CreateShelfGroupRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			groups []*model.ShelfGroup
			code   int
		)
		if groups, err = s.dao.FindShelfGroupsBySgId(ctx, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
		for _, group := range groups {
			if code <= group.Code {
				code = group.Code + 1
			}
			if req.Name == group.Name {
				err = ecode.AppendMessage(constant.ErrForbiddenAction, "存在重名分组")
				return
			}
		}
		if err = s.dao.Create(ctx, &model.ShelfGroup{
			Name:     req.Name,
			Code:     code,
			SgId:     req.Token.SgId,
			PStoreId: req.PStoreId,
			Status:   sql.NullBool{Valid: true, Bool: true},
			Operator: req.Token.EmpId,
		}); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 编辑货架分组名称
func (s *Service) UpdateShelfGroup(ctx context.Context, req *mall.UpdateShelfGroupRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var (
			group   *model.ShelfGroup
			existed bool
		)
		if group, err = s.dao.GetShelfGroup(ctx, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		if group.Name == req.Name {
			return
		}
		if existed, err = s.dao.CheckShelfGroupNameDup(
			ctx, req.Name, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
		if existed {
			err = ecode.AppendMessage(constant.ErrForbiddenAction, "存在重名分组")
			return
		}
		group.Name = req.Name
		group.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, group); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 删除货架分组
func (s *Service) DeleteShelfGroup(ctx context.Context, req *mall.CommonObjectRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var group *model.ShelfGroup
		if group, err = s.dao.GetShelfGroup(ctx, req.Id, req.Token.SgId, req.PStoreId); err != nil {
			if errors.Cause(err) == gorm.ErrRecordNotFound {
				err = constant.ErrObjectNotExist
				return
			}
			return
		}
		group.Status = sql.NullBool{}
		group.Operator = req.Token.EmpId
		if err = s.dao.Save(ctx, group); err != nil {
			return
		}
		return
	}); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	return
}

// 货架分组排序
func (s *Service) ArrangeShelfGroups(ctx context.Context, req *mall.ShelfGroupSortRequest) (
	resp *mall.DefaultResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	resp = &mall.DefaultResp{Status: true}
	if len(req.Ids) < 2 {
		return
	}
	if err = s.dao.Transaction(ctx, func(ctx context.Context) (err error) {
		var groups []*model.ShelfGroup
		if groups, err = s.dao.FindShelfGroupsBySgId(ctx, req.Token.SgId, req.PStoreId); err != nil {
			return
		}
		groupMap := make(map[uint32]*model.ShelfGroup)
		for _, group := range groups {
			groupMap[group.ID] = group
		}
		for code, groupId := range req.Ids {
			if group, ok := groupMap[groupId]; !ok {
				err = ecode.AppendMessage(constant.ErrNeedRefresh, "所选分组序列已更新，请刷新列表重试")
				return
			} else if group.Code != code {
				group.Code = code
				group.Operator = req.Token.EmpId
				if err = s.dao.Save(ctx, group); err != nil {
					return
				}
			}
		}
		return
	}); err != nil {
		return
	}
	return
}

// 查看商城货架类别存量可选列表下拉框
func (s *Service) GetShelfProdTypes(ctx context.Context, req *mall.CommonRequest) (
	resp *mall.ShelfProdTypesResp, err error) {
	if err = s.downstream.CheckMallPermission(ctx, req.Token, req.PStoreId); err != nil {
		return
	}
	var typeIds []uint32
	if typeIds, err = s.dao.FindShelfProdTypeIds(ctx, req.Token.SgId, req.PStoreId); err != nil {
		return
	}
	resp = &mall.ShelfProdTypesResp{}
	if len(typeIds) != 0 {
		if resp.ProdTypes, err = s.downstream.SelectionProdTypes(ctx, req.Token, typeIds); err != nil {
			return
		}
	} else {
		resp.ProdTypes = make([]*prod.SimpleProdTypeView, 0)
	}
	return
}

//检查商品是否在货架(删除检查，仅返回上架商品)
func (s *Service) ShelfProdsOnShelfCheck(ctx context.Context, req *mall.ShelfProdsOnShelfCheckRequest) (
	resp *mall.ShelfProdsOnShelfCheckResp, err error) {
	resp = &mall.ShelfProdsOnShelfCheckResp{}
	if resp.Ids, err = s.dao.FindShelfProdsByProdIdsWithoutPStoreId(ctx, req.SgId, req.Ids); err != nil {
		return
	}
	return
}
